#include "GY_GraphicsView.h"
#include <QDebug>
#include <QScrollBar>
#include <QApplication>
#include <Graphics/ContainerGraphics/GY_ContainerTransform.h>

GY_GraphicsView::GY_GraphicsView(QWidget *parent) : QGraphicsView(parent)
{
    setMouseTracking(true);
    //Y轴向调整 , y轴向上为正
    this->scale(1,-1);
    //初始化场景
    m_pScene = new GY_GraphicsScene(parent);
    setScene(m_pScene);
    //画笔
    QPen pen = QPen(QColor(255,0,255));
    pen.setWidth(0);
    //刻度
    m_pPathItem = new QGraphicsPathItem;
    m_pPathItem->setPen(pen);
    m_pPathItem->setZValue(9999);
    //因为画板垂直翻转了，刻度需要还原
    m_pPathItem->setTransform(QTransform::fromScale(1,-1));
    m_pScene->addItem(m_pPathItem);
    //左上角小黑框
    m_pLeftTopRect = new QGraphicsRectItem;
    m_pLeftTopRect->setZValue(99999);
    m_pLeftTopRect->setBrush(QBrush(QColor(0,0,0)));
    m_pLeftTopRect->setRect(0,0,20,20);
    m_pScene->addItem(m_pLeftTopRect);
    //抗锯齿
    setRenderHints(QPainter::Antialiasing);
    //滚动条事件
    QScrollBar *horizScrollBar = this->horizontalScrollBar();
    QScrollBar *verScrollBar = this->verticalScrollBar();
    connect(horizScrollBar,&QScrollBar::valueChanged,this,[=](){
        drawRulerLine();
    });
    connect(verScrollBar,&QScrollBar::valueChanged,this,[=](){
        drawRulerLine();
    });
    //当前选中的图元
    connect(m_pScene,&QGraphicsScene::selectionChanged,this,[=](){
        if(!m_pPathItem->isVisible()){
            return;
        }
        emit selectChange(m_pScene->selectedItems());
        drawEditPoint();
    });
    setViewportUpdateMode(QGraphicsView::FullViewportUpdate);//拖动时残影的解决
}
/**
 * @brief GY_GraphicsView::setSelectItem 设置选中的项
 * @param list
 */
void GY_GraphicsView::setSelectItem(QList<QGraphicsItem*> &list){
    if(!list.isEmpty())
    {
        //清理之前选中项
        QList<QGraphicsItem*> lastSelectItems = m_pScene->selectedItems();
        foreach(QGraphicsItem* item , lastSelectItems){
            if(item!=nullptr)
            {
                item->setSelected(false);
            }
        }
        //设置新的选中项
        foreach(QGraphicsItem* item , list){
            if(item!=nullptr)
            {
                item->setSelected(true);
            }
        }
    }
}

void GY_GraphicsView::updateEditorPoint(QGraphicsItem *item)
{
    //保持大小不变
    qreal w = 10/item->scale();
    QRectF rf = item->boundingRect();
    QString name = item->data(GY_ENUM::ObjectName).toString();
    //中心点,有则获取原对象，无则新创建
    GY_GraphicsCenterItem *cItem = nullptr;
    if(m_centerItemMap.contains(name)){
        cItem = m_centerItemMap.value(name);
    }else{
        cItem = new GY_GraphicsCenterItem(item);
        cItem->setPen(QPen(QColor(Qt::red)));
        cItem->setBrush(QBrush(QColor(Qt::red)));
        cItem->setData(GY_ENUM::ObjectName,name);
        m_centerItemMap.insert(name,cItem);
    }
    if(item->data(GY_ENUM::ObjectType)==1){
        GY_ContainerTransform *containerTransform = (GY_ContainerTransform*)item;
        QTransform transform;
        transform.scale(1/containerTransform->scaleX(),1/containerTransform->scaleY());
        cItem->setTransform(transform);
    }
    //保持大小不变
    cItem->setScale(1/m_Scale);
    //刷新到新的位置与大小,如果已经设置了中心点则以设置的为准，否则根据图元矩形区域计算中心点位置
    QPointF pf = item->data(GY_ENUM::CenterPointF).toPointF();
    if(pf.x() == 0.00001){
        cItem->setRect(QRectF((rf.x()*m_Scale+rf.width()*m_Scale/2-w/2),
                              (rf.y()*m_Scale+rf.height()*m_Scale/2-w/2),
                              w,
                              w));
    }else{
        cItem->setRect(pf.x()*m_Scale-w/2,pf.y()*m_Scale-w/2,w,w);
    }
    //更新当前图元的编辑点位置
    //保持大小不变
    w = w/item->scale();
    //编辑点,有则获取，无则创建，并刷新所在位置并保持大小不变
    QMap<QVariant,QPointF> editMap = item->data(GY_ENUM::EditPointF).value<QMap<QVariant,QPointF>>();
    QMapIterator<QVariant,QPointF> map(editMap);
    while(map.hasNext()){
        map.next();
        GY_GraphicsEditItem *eItem = nullptr;
        QString editName = QString("%1#%2").arg(name).arg(map.key().toString());
        if(m_editItemMap.contains(editName)){
            eItem = m_editItemMap.value(editName);
        }else{
            eItem = new GY_GraphicsEditItem(item);
            //编辑事件
            connect(eItem,SIGNAL(editPointFChange(QGraphicsItem * ,const QString &,const QPointF &)),this,SLOT(editPointFChange(QGraphicsItem *,const QString &,const QPointF &)));
            eItem->setPen(QPen(QColor(Qt::red)));
            eItem->setBrush(QBrush(QColor(Qt::red)));
            eItem->setData(GY_ENUM::ObjectName,editName);
            eItem->setZValue(999);
            m_editItemMap.insert(editName,eItem);
        }
        //如果是容器则反向变换编辑点
        if(item->data(GY_ENUM::ObjectType)==1){
            GY_ContainerTransform *containerTransform = (GY_ContainerTransform*)item;
            QTransform transform;
//            if(containerTransform->isRotation()){
//                transform.rotate(-containerTransform->containerRotation());
//            }
            transform.rotate(0);
            transform.scale(1/containerTransform->scaleX(),1/containerTransform->scaleY());
            eItem->setTransform(transform);
        }
        eItem->setScale(1/m_Scale);
        //更新
        eItem->setRect(QRectF(map.value().x()*m_Scale-w/2,map.value().y()*m_Scale-w/2,w,w));
    }
}

void GY_GraphicsView::setHideRuler(const bool &val)
{
    m_pPathItem->setVisible(!val);
    m_pLeftTopRect->setVisible(!val);
    if(val){
        m_pScene->removeItem(m_pPathItem);
        m_pScene->removeItem(m_pLeftTopRect);
        m_pScene->setSceneRect(0,0,0,0);
    }else{
        addItem(m_pPathItem);
        addItem(m_pLeftTopRect);
    }
}

/**
 * @brief clearItems 清空画布
 */
void GY_GraphicsView::clearItems()
{
    m_pScene->clear();
}

void GY_GraphicsView::editPointFChange(QGraphicsItem *item, const QString &key, const QPointF &p)
{
    int itemType=item->parentItem()->type();
    GY_Object* pObject=nullptr;
    QString propertyName=key.split("#").at(1);
    //2表示item是path
    if(itemType==2)
    {
        pObject=(GY_BasicsGraphicsObject*)(item->parentItem());
    }
    //10表示item是Group
    else if(itemType==10)
    {
        pObject=(GY_ContainerTransform*)(item->parentItem());

    }
    else
    {
        return;
    }
    pObject->updateProperty(propertyName,p);
    updateEditorPoint(item->parentItem());
    emit GY_ObjectChangeEvent(pObject,propertyName);
}

/**
 * @brief deleteGraphicItem 删除图元
 * @param item
 */
void GY_GraphicsView::deleteGraphicItem(QGraphicsItem *pItem)
{
    if(pItem!=nullptr)
    {
        m_pScene->removeItem(pItem);
    }
}

/**
 * @brief GY_GraphicsView::addItem  添加图元
 * @param item
 */
void GY_GraphicsView::addItem(QGraphicsItem *item)
{
    if(!m_pPathItem->isVisible()){
        item->setFlags(item->flags()
                       .setFlag(QGraphicsItem::ItemIsMovable,false)
                       .setFlag(QGraphicsItem::ItemIsSelectable,false));
        item->setAcceptHoverEvents(false);
    }
    m_pScene->addItem(item);
}
/**
 * @brief GY_GraphicsView::mouseMoveEvent 鼠标移动事件
 * @param event
 */
void GY_GraphicsView::mouseMoveEvent(QMouseEvent *event)
{
    //传递事件
    QGraphicsView::mouseMoveEvent(event);
    QPoint posPoint = event->pos();
    //因画板比例变化，移动轨迹也要发生对应变化*(1/m_Scale)
    QPointF offsetPos = (posPoint - m_PosAnchor)*(1/m_Scale);
    //画板Y轴翻转，移动轨迹也要取反
    offsetPos.ry()*=-1;
    if(m_IsMousePressed){
        //缩放比例时以鼠标为锚点缩放
        setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
        //新的中心点位置
        QPointF pf = m_CenterAnchor - offsetPos;
        //上下反向
//        pf.ry()*=-1;
        //视图观察场景点，设置pf为窗口中心点（实际上还是移动的scene）
        centerOn(pf);
        drawRulerLine();
    }
    emit mousePointF(event->localPos());
}
/**
 * @brief GY_GraphicsView::mousePressEvent  鼠标按下事件
 * @param event
 */
void GY_GraphicsView::mousePressEvent(QMouseEvent *event)
{
    //传递事件
    QGraphicsView::mousePressEvent(event);
    if(this->scene() == nullptr || !m_pPathItem->isVisible()){
        //记录鼠标位置及状态
        emit mouseIsPress();
        return;
    }
    //鼠标左键为选择模式，右键为画板拖拽模式
    if(event->button() == Qt::RightButton){
        this->setDragMode(QGraphicsView::NoDrag);
        //记录鼠标位置及状态
        QPoint posPoint = event->pos();
        //得到屏幕中心点的scene坐标
        m_CenterAnchor = mapToScene(width()/2, height()/2);
        //储存鼠标按下时点位
        m_PosAnchor = posPoint;
        m_IsMousePressed = true;
    }else if(event->button() == Qt::LeftButton){
        this->setDragMode(QGraphicsView::RubberBandDrag);
    }
}
/**
 * @brief GY_GraphicsView::mouseReleaseEvent 鼠标结束事件
 * @param event
 */
void GY_GraphicsView::mouseReleaseEvent(QMouseEvent *event)
{
    //传递事件
    QGraphicsView::mouseReleaseEvent(event);
    m_IsMousePressed = false;
}

void GY_GraphicsView::dragEnterEvent(QDragEnterEvent *event)
{
    if (event->mimeData()->hasFormat("application/x-dnditemdata")) {
        if (event->source() == this) {
            event->setDropAction(Qt::MoveAction);
            event->accept();
        } else {
            event->acceptProposedAction();
        }
    } else {
        event->ignore();
    }
}

void GY_GraphicsView::dragMoveEvent(QDragMoveEvent *event)
{
    if (event->mimeData()->hasFormat("application/x-dnditemdata")) {
        if (event->source() == this) {
            event->setDropAction(Qt::MoveAction);
            event->accept();
        } else {
            event->acceptProposedAction();
        }
    } else {
        event->ignore();
    }
}

void GY_GraphicsView::dropEvent(QDropEvent *event)
{
    if(event->mimeData()->hasFormat("application/x-dnditemdata"))
    {
        QByteArray itemData = event->mimeData()->data("application/x-dnditemdata");
        QDataStream dataStream(&itemData, QIODevice::ReadOnly);
        QVariant objectGuid;
        QString objectName;
        QVariant objectType;
        QString dropAreaName;
        dataStream >> objectGuid >> objectName >> objectType >> dropAreaName;
        emit sendDropEvent(objectGuid,objectName,objectType,dropAreaName);

        if (event->source() == this) {
            event->setDropAction(Qt::MoveAction);
            event->accept();
        } else {
            event->acceptProposedAction();
        }
    } else {
        event->ignore();
    }
}

/**
 * @brief GY_GraphicsView::wheelEvent  鼠标滚轮放大缩水
 * @param event
 */
void GY_GraphicsView::wheelEvent(QWheelEvent *event)
{
    //获取鼠标滚轮的距离
    int wheelDeltaValue = event->delta();
    //向上滚动，放大
    if (wheelDeltaValue > 0){
        if(m_Scale*1.1 > 8){
            return;
        }
        this->scale(1.1, 1.1);
        m_Scale*=1.1;
    }else{
        if(m_Scale*1.1 < 0.14){
            return;
        }
        //向下滚动，缩小
        this->scale(1.0 / 1.1, 1.0 / 1.1);
        m_Scale*=(1.0/1.1);
    }
    if(!m_pPathItem->isVisible()){
        return;
    }
    emit viewScale(m_Scale);
    drawRulerLine();
    drawEditPoint();
}
/**
 * @brief GY_GraphicsView::resizeEvent  窗口大小改变事件处理
 */
void GY_GraphicsView::resizeEvent(QResizeEvent *)
{
    drawRulerLine();
}
/**
 * @brief GY_GraphicsView::drawRulerLine  绘制刻度线
 */
void GY_GraphicsView::drawRulerLine()
{
    //场景缩放比例
    m_pPathItem->setScale(1/m_Scale);
    //不显示刻度及文字
    if(!m_pPathItem->isVisible()){
        for(int i = 0 ; i < m_TextItemList.size() ; i ++){
            m_TextItemList.value(i)->setVisible(false);
        }
        return;
    }
    //设置参照坐标点
    QPointF pf = this->mapToScene(0,0);
    //左上角小黑框
    m_pLeftTopRect->setScale(1/m_Scale);
    m_pLeftTopRect->setPos(pf.rx() , pf.ry()-20/m_Scale);
    //参照点映射区域位置及大小
    QPolygonF poly = this->mapToScene(0,0,this->width(),this->height());
    //画板与视图窗口的比例
    qreal hWidthScale = this->width()/poly.boundingRect().width();
//    qreal vHeightScale = this->height()/poly.boundingRect().height();
    //根据参照坐标点还原视图左上角的坐标点
    pf.rx() *= m_Scale;
    pf.ry() *= m_Scale;
    QPainterPath path = m_pPathItem->path();
    //删除之前的绘制
    path.clear();
    //最小刻度单位
    qreal minPix = 5.0;
    //可视区域的最大分段数，刻度数显示的最小像素间隔的距离为50px
    qreal hMinNum = (this->width()/50.0);
    qreal vMinNum = (this->height()/50.0);
    //每个大分段占多少像素
    qreal hMinNumPix = poly.boundingRect().width()/(hMinNum*1.0);
    qreal hIntMinNumPix = qRound(hMinNumPix/10.0)*10;//处理成10的倍数
    qreal vMinNumPix = poly.boundingRect().height()/(vMinNum*1.0);
    qreal vIntMinNumPix = qRound(vMinNumPix/10.0)*10;//处理成10的倍数
    //视图左上角坐标换成10的整数倍的位置，冗余1个刻度单位，避免显示不全
    QPointF polyPointFStart = QPointF((qRound(poly.boundingRect().x()/hIntMinNumPix)-1)*hIntMinNumPix,
                                      (qRound(poly.boundingRect().y()/vIntMinNumPix)-1)*vIntMinNumPix);
    //记录起点坐标 , 并垂直翻转
    QPointF oldPoint = QPointF(pf.rx(),pf.ry()*-1);
    //坐标还原
    pf.rx() = polyPointFStart.rx()*m_Scale;
    pf.ry() = polyPointFStart.ry()*m_Scale;
    //移动到起始绘制点
    path.moveTo(oldPoint.rx(),oldPoint.ry());
    //最小刻度单位长度，因为缩放比例是一样的所以宽高单位长度一样
    minPix = hIntMinNumPix*hWidthScale/10;
    //只绘制视图可视范围内的刻度线，冗余30个单位刻度，避免显示不全
    qreal w = width()/minPix + 30;
    qreal h = height()/minPix + 30;
    //刻度线集合，避免重复大量的new对象
    int index = 0;
    //横向刻度线
    for(int i = 0; i < w ; i ++){
        path.lineTo(pf.rx()+i*minPix,oldPoint.ry()+(i%10==0?15:(i%5==0?8:5)));
        path.moveTo(pf.rx()+(i+1)*minPix,oldPoint.ry());
        if(i%10==0){
            QGraphicsTextItem *item = nullptr;
            //从已有对象中获取
            if(m_TextItemList.size() > index){
                item = m_TextItemList.at(index);
            }else{
                item = new QGraphicsTextItem(m_pPathItem);
                item->setDefaultTextColor(QColor(0,255,255));
                m_TextItemList.append(item);
            }
            //水平显示
            item->setRotation(0);
            item->setVisible(true);
            item->setPlainText(QString::number( (polyPointFStart.rx()+i*hIntMinNumPix/10) ));
            item->setPos( (pf.rx()+i*minPix),(oldPoint.ry()+5));
            index++;
        }
    }
    //垂直刻度线
    path.moveTo(oldPoint.rx(),pf.ry()*-1);
    for(int i = 0; i < h ; i ++){
        path.lineTo(oldPoint.rx()+(i%10==0?15:(i%5==0?8:5)),(pf.ry()+i*minPix)*-1);
        path.moveTo(oldPoint.rx(),(pf.ry()+(i+1)*minPix)*-1);
        if(i%10==0){
            QGraphicsTextItem *item = nullptr;
            if(m_TextItemList.size() > index){
                item = m_TextItemList.at(index);
                //默认水平显示
                item->setRotation(0);
            }else{
                item = new QGraphicsTextItem(m_pPathItem);
                item->setDefaultTextColor(QColor(0,255,255));
                m_TextItemList.append(item);
            }
            //垂直显示
            item->setRotation(-90);
            item->setVisible(true);
            item->setPlainText(QString::number( (polyPointFStart.ry()+i*vIntMinNumPix/10) ));
            item->setPos(oldPoint.rx()+5,(pf.ry()+i*minPix)*-1);
            index++;
        }
    }
    //清理掉多余的文本对象
    for(int i = index ; i < m_TextItemList.size() ; i ++){
        m_TextItemList.value(i)->setVisible(false);
    }
    m_pPathItem->setPath(path);
}


/**
 * @brief GY_GraphicsView::drawCenterPoint  绘制编辑点图元
 */
void GY_GraphicsView::drawEditPoint()
{
    //编辑点的宽高
    qreal w = 10;
    //清理上次选中的项但这次没有被选中
    foreach(QGraphicsItem* item , selectItems){
        if(item->isSelected()){
            continue;
        }
        //移动中心点
        QString name = item->data(GY_ENUM::ObjectName).toString();
        if(m_centerItemMap.contains(name)){
            m_centerItemMap.value(name)->hide();
            m_centerItemMap.value(name)->deleteLater();
            m_centerItemMap.remove(name);
        }
        //移除可编辑点
        QMap<QVariant,QPointF> editMap = item->data(GY_ENUM::EditPointF).value<QMap<QVariant,QPointF>>();
        QMapIterator<QVariant,QPointF> map(editMap);
        while(map.hasNext()){
            map.next();
            QString editName = QString("%1#%2").arg(name).arg(map.key().toString());
            if(m_editItemMap.contains(editName)){
                if(!item->hasFocus()){
                    m_editItemMap.value(editName)->hide();
                    delete m_editItemMap.value(editName);
                    m_editItemMap.remove(editName);
                }
            }
        }
    }
    selectItems = m_pScene->selectedItems();
    foreach(QGraphicsItem* item , selectItems){
        updateEditorPoint(item);
        //保持大小不变
        w = w/item->scale();
        //编辑点,有则获取，无则创建，并刷新所在位置并保持大小不变
        QMap<QVariant,QPointF> editMap = item->data(GY_ENUM::EditPointF).value<QMap<QVariant,QPointF>>();
        QMapIterator<QVariant,QPointF> map(editMap);
        QString name = item->data(GY_ENUM::ObjectName).toString();
        while(map.hasNext()){
            map.next();
            GY_GraphicsEditItem *eItem = nullptr;
            QString editName = QString("%1#%2").arg(name).arg(map.key().toString());
            if(m_editItemMap.contains(editName)){
                eItem = m_editItemMap.value(editName);
            }else{
                eItem = new GY_GraphicsEditItem(item);
                eItem->setObjectName(map.key().toString());
                //编辑事件
                connect(eItem,SIGNAL(editPointFChange(QGraphicsItem * ,const QString &,const QPointF &)),this,SLOT(editPointFChange(QGraphicsItem *,const QString &,const QPointF &)));
                eItem->setPen(QPen(QColor(Qt::red)));
                eItem->setBrush(QBrush(QColor(Qt::red)));
                eItem->setData(GY_ENUM::ObjectName,editName);
                eItem->setZValue(999);
                m_editItemMap.insert(editName,eItem);
            }
            //如果是容器则反向变换编辑点
            if(item->data(GY_ENUM::ObjectType)==1){
                GY_ContainerTransform *containerTransform = (GY_ContainerTransform*)item;
                QTransform transform;
//                if(containerTransform->isRotation()){
//                    transform.rotate(-containerTransform->containerRotation());
//                }
                transform.rotate(0);
                transform.scale(1/containerTransform->scaleX(),1/containerTransform->scaleY());
                eItem->setTransform(transform);
            }
            eItem->setScale(1/m_Scale);
            //更新
            eItem->setRect(QRectF(map.value().x()*m_Scale-w/2,map.value().y()*m_Scale-w/2,w,w));
        }
    }
}
